/**
 * 
 */
package com.m7012e.a_remote.commons;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketTimeoutException;

import com.leoj.utils.Handler;
import com.m7012e.a_remote.ar_listeners.exception.IncorrectDataException;
import com.m7012e.a_remote.communication.Message;

/**
 * @author leoj
 *
 */
public class ARemoteMulticastListener extends Thread {
	private MulticastSocket _multiSock;
	private InetAddress _group;
	private byte[] _buf;
	private DatagramPacket _packet;
	private boolean _running;
	private Handler<IncomingMulticastMessage> _msgHandler;
	
	/**
	 * @throws IOException 
	 * 
	 */
	public ARemoteMulticastListener(String ipAddress, int port, int bufSize, Handler<IncomingMulticastMessage> msgHandler) throws IOException {
		_multiSock = new MulticastSocket(port);
		_group = InetAddress.getByName(ipAddress);
		_multiSock.joinGroup(_group);
		
		// will allow the thread to make stop every second and half and therefore will avoid it to block for longer than that
		_multiSock.setSoTimeout(1500);
		
		_buf = new byte[bufSize];
		_packet = new DatagramPacket(_buf, _buf.length);
		
		_msgHandler = msgHandler;
	}
	/**
	 * @throws IOException 
	 * 
	 */
	public ARemoteMulticastListener(Handler<IncomingMulticastMessage> msgHandler) throws IOException {
		this("224.0.0.251", 8706, 1024, msgHandler);
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	@Override
	public void run() {
		_running = true;
		while(_running){
			try {
				//Wait for a incomming request
				_multiSock.receive(_packet); // this call is blocking
				System.out.println("DEBUG: Received data from: " + _packet.getAddress().toString() +
				    ":" + _packet.getPort() + " with length: " +
				    _packet.getLength());
				Message msg = readMessage(_packet.getData());
				_msgHandler.handle(new IncomingMulticastMessage(msg, _packet.getAddress()));
			} catch (SocketTimeoutException e){
				System.out.println("timeout for the UDP multicast listener");
			} catch (IOException e) {
				e.printStackTrace();
			} catch (IncorrectDataException e) {
				System.out.println("multicast data ignored !");
			}
		}
	}
	
	public static Message readMessage(byte[] byteMsg) throws IOException, IncorrectDataException{
		ObjectInputStream objectStream = new ObjectInputStream(new ByteArrayInputStream(byteMsg, 0, byteMsg.length));
		Object obj;
		try {
			obj = objectStream.readObject();
			if (obj instanceof Message) {
				return (Message) obj;
			} //else : do nothing, the exception will be launched right after this block
		} catch (ClassNotFoundException e) {
			//do nothing, the exception will be launched right after this block
		}
			throw new IncorrectDataException();
	}
	
	public void stopAsap(){ _running = false; }
}
